home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / Gnuplot / Source / scanner.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-02  |  9.8 KB  |  384 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: scanner.c%v 3.38.2.74 1993/02/19 00:57:30 woo Exp woo $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - scanner.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software is provided "as is" without express or implied warranty.
  21.  * 
  22.  *
  23.  * AUTHORS
  24.  * 
  25.  *   Original Software:
  26.  *     Thomas Williams,  Colin Kelley.
  27.  * 
  28.  *   Gnuplot 2.0 additions:
  29.  *       Russell Lang, Dave Kotz, John Campbell.
  30.  *
  31.  *   Gnuplot 3.0 additions:
  32.  *       Gershon Elber and many others.
  33.  * 
  34.  * Send your comments or suggestions to 
  35.  *  info-gnuplot@dartmouth.edu.
  36.  * This is a mailing list; to join it send a note to 
  37.  *  info-gnuplot-request@dartmouth.edu.  
  38.  * Send bug reports to
  39.  *  bug-gnuplot@dartmouth.edu.
  40.  */
  41.  
  42. #include <stdio.h>
  43. #include <ctype.h>
  44. #include "plot.h"
  45.  
  46. #ifdef AMIGA_AC_5
  47. #define O_RDONLY    0
  48. int open(const char * _name, int _mode, ...);
  49. int close(int);
  50. #endif
  51.  
  52. #ifdef vms
  53.  
  54. #include stdio
  55. #include descrip
  56. #include errno
  57.  
  58. #define MAILBOX "PLOT$MAILBOX"
  59. #define pclose(f) fclose(f)
  60.  
  61. #endif /* vms */
  62.  
  63.  
  64. #define isident(c) (isalnum(c) || (c) == '_')
  65.  
  66. #ifndef STDOUT
  67. #define STDOUT 1
  68. #endif
  69.  
  70. #define LBRACE '{'
  71. #define RBRACE '}'
  72.  
  73. #define APPEND_TOKEN {token[t_num].length++; current++;}
  74.  
  75. #define SCAN_IDENTIFIER while (isident(expression[current + 1]))\
  76.                 APPEND_TOKEN
  77.  
  78. extern struct lexical_unit token[MAX_TOKENS];
  79.  
  80. static int t_num;    /* number of token I'm working on */
  81.  
  82. #ifndef AMIGA_SC_6_1
  83. char *strcat(), *strcpy(), *strncpy();
  84. #endif /* !AMIGA_SC_6_1 */
  85.  
  86. /*
  87.  * scanner() breaks expression[] into lexical units, storing them in token[].
  88.  *   The total number of tokens found is returned as the function value.
  89.  *   Scanning will stop when '\0' is found in expression[], or when token[]
  90.  *     is full.
  91.  *
  92.  *     Scanning is performed by following rules:
  93.  *
  94.  *    Current char    token should contain
  95.  *     -------------    -----------------------
  96.  *    1.  alpha,_    all following alpha-numerics
  97.  *    2.  digit    0 or more following digits, 0 or 1 decimal point,
  98.  *                0 or more digits, 0 or 1 'e' or 'E',
  99.  *                0 or more digits.
  100.  *    3.  ^,+,-,/    only current char
  101.  *        %,~,(,)
  102.  *        [,],;,:,
  103.  *        ?,comma
  104.  *    4.  &,|,=,*    current char; also next if next is same
  105.  *    5.  !,<,>    current char; also next if next is =
  106.  *    6.  ", '    all chars up until matching quote
  107.  *    7.  #        this token cuts off scanning of the line (DFK).
  108.  *
  109.  *            white space between tokens is ignored
  110.  */
  111. scanner(expression)
  112. char expression[];
  113. {
  114. register int current;    /* index of current char in expression[] */
  115. register int quote;
  116. char brace;
  117.  
  118.     for (current = t_num = 0;
  119.         t_num < MAX_TOKENS && expression[current] != '\0';
  120.         current++) {
  121. again:
  122.         if (isspace(expression[current]))
  123.             continue;                        /* skip the whitespace */
  124.         token[t_num].start_index = current;
  125.         token[t_num].length = 1;
  126.         token[t_num].is_token = TRUE;    /* to start with...*/
  127.  
  128.         if (expression[current] == '`') {
  129.             substitute(&expression[current],MAX_LINE_LEN - current);
  130.             goto again;
  131.         }
  132.         /* allow _ to be the first character of an identifier */
  133.         if (isalpha(expression[current]) || expression[current] == '_') {
  134.             SCAN_IDENTIFIER;
  135.         } else if (isdigit(expression[current]) || expression[current] == '.'){
  136.             token[t_num].is_token = FALSE;
  137.             token[t_num].length = get_num(&expression[current]);
  138.             current += (token[t_num].length - 1);
  139.         } else if (expression[current] == LBRACE) {
  140.             token[t_num].is_token = FALSE;
  141.             token[t_num].l_val.type = CMPLX;
  142. #ifdef __PUREC__
  143.             { char    l[80];
  144.             if ((sscanf(&expression[++current],"%lf,%lf%[ }]s",
  145.                 &token[t_num].l_val.v.cmplx_val.real,
  146.                 &token[t_num].l_val.v.cmplx_val.imag,
  147.                 &l)    != 3) || (!strchr(l, RBRACE))  )
  148.                     int_error("invalid complex constant",t_num);
  149.             }
  150. #else
  151.             if ((sscanf(&expression[++current],"%lf , %lf %c",
  152.                 &token[t_num].l_val.v.cmplx_val.real,
  153.                 &token[t_num].l_val.v.cmplx_val.imag,
  154.                 &brace) != 3) || (brace != RBRACE))
  155.                     int_error("invalid complex constant",t_num);
  156. #endif
  157.             token[t_num].length += 2;
  158.             while (expression[++current] != RBRACE) {
  159.                 token[t_num].length++;
  160.                 if (expression[current] == '\0')            /* { for vi % */
  161.                     int_error("no matching '}'", t_num);
  162.             }
  163.         } else if (expression[current] == '\'' || expression[current] == '\"'){
  164.             token[t_num].length++;
  165.             quote = expression[current];
  166.             while (expression[++current] != quote) {
  167.                 if (!expression[current]) {
  168.                     expression[current] = quote;
  169.                     expression[current+1] = '\0';
  170.                     break;
  171.                 } else
  172.                     token[t_num].length++;
  173.             }
  174.         } else switch (expression[current]) {
  175.              case '#':        /* DFK: add comments to gnuplot */
  176.                   goto endline; /* ignore the rest of the line */
  177.             case '^':
  178.             case '+':
  179.             case '-':
  180.             case '/':
  181.             case '%':
  182.             case '~':
  183.             case '(':
  184.             case ')':
  185.             case '[':
  186.             case ']':
  187.             case ';':
  188.             case ':':
  189.             case '?':
  190.             case ',':
  191.                 break;
  192.             case '&':
  193.             case '|':
  194.             case '=':
  195.             case '*':
  196.                 if (expression[current] == expression[current + 1])
  197.                     APPEND_TOKEN;
  198.                 break;
  199.             case '!':
  200.             case '<':
  201.             case '>':
  202.                 if (expression[current + 1] == '=')
  203.                     APPEND_TOKEN;
  204.                 break;
  205.             default:
  206.                 int_error("invalid character",t_num);
  207.             }
  208.         ++t_num;    /* next token if not white space */
  209.     }
  210.  
  211. endline:                    /* comments jump here to ignore line */
  212.  
  213. /* Now kludge an extra token which points to '\0' at end of expression[].
  214.    This is useful so printerror() looks nice even if we've fallen off the
  215.    line. */
  216.  
  217.         token[t_num].start_index = current;
  218.         token[t_num].length = 0;
  219.     return(t_num);
  220. }
  221.  
  222.  
  223. get_num(str)
  224. char str[];
  225. {
  226. double atof();
  227. register int count = 0;
  228. long atol();
  229. register long lval;
  230.  
  231.     token[t_num].is_token = FALSE;
  232.     token[t_num].l_val.type = INTGR;        /* assume unless . or E found */
  233.     while (isdigit(str[count]))
  234.         count++;
  235.     if (str[count] == '.') {
  236.         token[t_num].l_val.type = CMPLX;
  237.         while (isdigit(str[++count]))    /* swallow up digits until non-digit */
  238.             ;
  239.         /* now str[count] is other than a digit */
  240.     }
  241.     if (str[count] == 'e' || str[count] == 'E') {
  242.         token[t_num].l_val.type = CMPLX;
  243. /* modified if statement to allow + sign in exponent
  244.    rjl 26 July 1988 */
  245.         count++;
  246.         if (str[count] == '-' || str[count] == '+')
  247.             count++;
  248.         if (!isdigit(str[count])) {
  249.             token[t_num].start_index += count;
  250.             int_error("expecting exponent",t_num);
  251.         }
  252.         while (isdigit(str[++count]))
  253.             ;
  254.     }
  255.     if (token[t_num].l_val.type == INTGR) {
  256.          lval = atol(str);
  257.         if ((token[t_num].l_val.v.int_val = lval) != lval)
  258.             int_error("integer overflow; change to floating point",t_num);
  259.     } else {
  260.         token[t_num].l_val.v.cmplx_val.imag = 0.0;
  261.         token[t_num].l_val.v.cmplx_val.real = atof(str);
  262.     }
  263.     return(count);
  264. }
  265.  
  266. #if defined(unix) || defined(vms) || defined(PIPES) || (defined(ATARI) && defined(__PUREC__))
  267.  
  268. substitute(str,max)            /* substitute output from ` ` */
  269. char *str;
  270. int max;
  271. {
  272. register char *last;
  273. register int i,c;
  274. register FILE *f;
  275. #ifdef AMIGA_AC_5
  276. int fd;
  277. #else
  278. #if defined(ATARI) && defined(__PUREC__)
  279. char    *atari_tmpfile;
  280. char    *atari_pgm[MAX_LINE_LEN+100];
  281. #else
  282. FILE *popen();
  283. #endif /* ATARI && PUREC */
  284. #endif
  285. static char pgm[MAX_LINE_LEN+1],output[MAX_LINE_LEN+1];
  286.  
  287. #ifdef vms
  288. int chan;
  289. static $DESCRIPTOR(pgmdsc,pgm);
  290. static $DESCRIPTOR(lognamedsc,MAILBOX);
  291. #endif /* vms */
  292.  
  293.     i = 0;
  294.     last = str;
  295.     while (*(++last) != '`') {
  296.         if (*last == '\0')
  297.             int_error("unmatched `",t_num);
  298.         pgm[i++] = *last;
  299.     }
  300.     pgm[i] = '\0';        /* end with null */
  301.     max -= strlen(last);    /* max is now the max length of output sub. */
  302.   
  303. #ifdef vms
  304.       pgmdsc.dsc$w_length = i;
  305.        if (!((vaxc$errno = sys$crembx(0,&chan,0,0,0,0,&lognamedsc)) & 1))
  306.            os_error("sys$crembx failed",NO_CARET);
  307.    
  308.        if (!((vaxc$errno = lib$spawn(&pgmdsc,0,&lognamedsc,&1)) & 1))
  309.            os_error("lib$spawn failed",NO_CARET);
  310.    
  311.        if ((f = fopen(MAILBOX,"r")) == NULL)
  312.            os_error("mailbox open failed",NO_CARET);
  313. #else /* vms */
  314. #if defined(ATARI) && defined(__PUREC__)
  315.         if (system(NULL) == 0)
  316.             os_error("no command shell");
  317.         if ((strlen(atari_tmpfile) + strlen(pgm) + 5) > MAX_LINE_LEN+100)
  318.             os_error("sorry, command to long");
  319.         atari_tmpfile = tmpnam(NULL);
  320.         strcpy(atari_pgm, pgm);
  321.         strcat(atari_pgm, " >> ");
  322.         strcat(atari_pgm, atari_tmpfile);
  323.         system(atari_pgm);
  324.         if ((f = fopen(atari_tmpfile, "r")) == NULL)
  325. #else
  326. #ifdef AMIGA_AC_5
  327.       if ((fd = open(pgm,"O_RDONLY")) == -1)
  328. #else
  329.       if ((f = popen(pgm,"r")) == NULL)
  330. #endif
  331. #endif    /* ATARI && PUREC */
  332.           os_error("popen failed",NO_CARET);
  333. #endif /* vms */
  334.  
  335.     i = 0;
  336.     while ((c = getc(f)) != EOF) {
  337.         output[i++] = ((c == '\n') ? ' ' : c);    /* newlines become blanks*/
  338.         if (i == max) {
  339. #ifdef AMIGA_AC_5
  340.             (void) close(fd);
  341. #else
  342. #if defined(ATARI) && defined(__PUREC__)
  343.             (void) fclose(f);
  344.             (void) unlink(atari_tmpfile);
  345. #else
  346.             (void) pclose(f);
  347. #endif /* ATARI && PUREC */
  348. #endif
  349.             int_error("substitution overflow", t_num);
  350.         }
  351.     }
  352. #ifdef AMIGA_AC_5
  353.     (void) close(fd);
  354. #else
  355. #if defined(ATARI) && defined(__PUREC__)
  356.     (void) fclose(f);
  357.     (void) unlink(atari_tmpfile);
  358. #else
  359.     (void) pclose(f);
  360. #endif /* ATARI && PUREC */
  361. #endif
  362.  
  363.     if (i + strlen(last) > max)
  364.         int_error("substitution overflowed rest of line", t_num);
  365.     (void) strncpy(output+i,last+1,MAX_LINE_LEN-i);
  366.                                     /* tack on rest of line to output */
  367.     (void) strcpy(str,output);                /* now replace ` ` with output */
  368.     screen_ok = FALSE;
  369. }
  370.  
  371. #else /* unix || vms || PIPES || ATARI && PUREC */
  372.  
  373. #ifdef __ZTC__
  374. substitute(char *str,int max)
  375. #else
  376. substitute()
  377. #endif
  378. {
  379.     char line[100];
  380.  
  381.     int_error( strcat(strcpy(line,"substitution not supported by "),OS),t_num);
  382. }
  383. #endif /* unix || vms || PIPES || ATARI && PUREC */
  384.